package com.open.gen.util;

import com.open.gen.po.MetaData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.*;

/**
 * 元数据映射类
 */
public class MetaMapping {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    // 表名
    private String tableName;

    // 表的各列及元数据
    private List<MetaData> columnList = new ArrayList<MetaData>();

    Map<String, MetaData> metaDataMap = new HashMap<String, MetaData>();

    public MetaMapping(String tableName) {
        try {
            this.tableName = tableName;
            this.parseMetaData();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<MetaData> getColumnList() {
        return columnList;
    }

    public Map<String, MetaData> getMetaDataMap() {
        return metaDataMap;
    }

    /**
     * 取得表的元数据，即取得各列名及类型
     *
     * @return 列名及其列类型：LinkedHashMap<String, MyMetaData> map
     * @throws Exception
     */
    protected void parseMetaData() throws Exception {

        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = DBResource.getConnection();
            String schemaName = conn.getSchema();

            DatabaseMetaData databaseMetaData = conn.getMetaData();

            // 定位主键字段
            Set<String> keySet = new HashSet<String>();
            rs = databaseMetaData.getPrimaryKeys(conn.getCatalog(), schemaName, tableName);
            while (rs.next()) {
                String pk = rs.getString("COLUMN_NAME").toLowerCase();
                keySet.add(pk);
            }
            rs.close();

            rs = databaseMetaData.getColumns(null, schemaName, tableName, "%");
            while (rs.next()) {
                String colName = rs.getString("COLUMN_NAME").toLowerCase(); // 列名
                int colType = rs.getInt("DATA_TYPE"); // 对应的java.sql.Types类型
                String colTypeName = rs.getString("TYPE_NAME");// java.sql.Types类型名称
                String comment = rs.getString("REMARKS"); // 注释
                String fileldName = MappingUtil.getFieldName(colName); // 列名转成驼峰型

                // 是否是主键
                boolean isPk = false;
                if (keySet.contains(colName)) {
                    isPk = true;
                }

                MetaData metaData = new MetaData();
                metaData.setColName(colName);
                metaData.setColType(colType);
                metaData.setColTypeName(colTypeName);
                metaData.setComment(comment);
                metaData.setFieldName(fileldName);
                metaData.setPk(isPk);
                metaDataMap.put(colName, metaData);
            }

            // 获取列元数据
            String sql = "SELECT * FROM " + tableName + " WHERE 1=2";
            stmt = conn.prepareStatement(sql);
            rs = stmt.executeQuery();

            ResultSetMetaData rsmd = rs.getMetaData();
            for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                String colName = rsmd.getColumnName(i).toLowerCase();
                MetaData metaData = metaDataMap.get(colName);
                metaData.setPrecision(rsmd.getPrecision(i));
                metaData.setScale(rsmd.getScale(i));

                // 把列类型映射为类属性类型
                metaData.setFieldType(reflectToFieldType(metaData.getColType(), metaData.getScale()));
                columnList.add(metaData);
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (stmt != null) {
                    stmt.close();
                }
                DBResource.freeConnection(conn);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 把列类型映射为类属性类型
     *
     * @param colType
     * @return
     * @throws Exception
     */
    private String reflectToFieldType(int colType, int scale) throws Exception {

        switch (colType) {
            case Types.BIT:
                return "int";
            case Types.TINYINT:
                return "int";
            case Types.SMALLINT:
                return "int";
            case Types.INTEGER:
                return "int";
            case Types.BIGINT:
                return "Long";

            case Types.FLOAT:
                return "float";
            case Types.REAL:
                return "double";
            case Types.DOUBLE:
                return "double";
            case Types.NUMERIC:
                return "double";
            case Types.DECIMAL:
                return "double";
            case Types.CHAR:
                return "String";
            case Types.VARCHAR:
                return "String";
            case Types.LONGVARCHAR:
                return "String";

            case Types.DATE:
                return "String";
            case Types.TIME:
                return "String";
            case Types.TIMESTAMP:
                return "String";

            case Types.BINARY:
                return "String";
            case Types.VARBINARY:
                return "String";
            case Types.LONGVARBINARY:
                return "String";

            case Types.BLOB:
                return "String";
            case Types.CLOB:
                return "String";
        }

        throw new Exception("不能识别的列类型:" + colType);
    }
}
